<?php
/**
 * @package    panel
 * @subpackage panel.application
 */
/**
 * R/W API to panel.application request data.
 *
 *<pre>
 * Example #1
 *
 * Ajax call from CP js environment:
 *
 * panel.ajax({
 *
 *	_p  : "my_rrp_processor",
 *	_pa : "action_say_hello_to_me",
 *	_rt : "text/plain"
 *	_pd : {
 *
 *  	my_name: "Krevedko"
 *
 *  },
 *
 *  onComplete: function(response) {
 *
 *  	alert(response);
 *  	// Alert with "Hello Krevedko!";
 *
 *  }
 *
 * }).request();
 *</pre>
 *<pre>
 * Example #2
 *
 * How-To Encode data:
 *
 * Flow DATA -> URL Encode -> JSON Serialize -> Base64
 * # // From JS Ajax to Panel
 *
 * # data = { val1: encodeURIComponent("Value 1 test value"), val2: { nestedValue1: 123, nestedValue2: 456 } }
 * #> Object val1=Value%201%20test%20value val2=Object
 *
 * # data = Ext.ux.util.base64.encode( Ext.util.JSON.encode(data) );
 * #> "eyJ2YWwxIjoiVmFsdWUlMjAxJTIwdGVzdCUyMHZhbHVlIiwidmFsMiI6eyJuZXN0ZWRWYWx1ZTEiOjEyMywibmVzdGVkVmFsdWUyIjo0NTZ9fQ=="
 *
 * # AJAX("panel?_p=somerrp&_pa=someaction", "POST", { _pd: data });
 *</pre>
 *
 * @author Dmitry Bakaleinik (code)
 */
abstract class panel__application__request
	implements maf__mvc__i__model__static {

	/**
	 * Name of request parameter,
	 * which designate processing controller (RRP) name.
	 * Used by panel.application to call RRP.
	 *
	 * Example: panel/?_p=websites
	 *
	 * @var string
	 */
	const PROCESSOR__NAME   = "_p";

	/**
	 * Name of request parameter,
	 * which designate processing controller (RRP) action name.
	 * Used by RRP controlled to call processing method.
	 *
	 * Example: panel/?_p=websites&_pa=get_websites_list
	 *
	 * @var string
	 */
	const PROCESSOR__ACTION = "_pa";

	/**
	 * Request parameter containing the request data that
	 * (URL-encoded if needed) JSON serialized and encoded by base64.
	 *
	 * URL encode required only for textual data which can contain [a-z/0-9] characters/symbols.
	 *
	 * @see Example #1
	 * @var string
	 */
	const PROCESSOR__DATA   = "_pd";

	/**
	 * Name of request parameter which designate a content type of response.
	 *
	 *<pre>
	 * Example:
	 * panel/?_p=websites&_pa=get_websites_list&_rt=text/json -> Response will JSON encoded data
	 * panel/?_p=websites&_pa=get_websites_list&_rt=text/xml  -> Response will XML encoded data
	 *</pre>
	 *
	 * @var string
	 */
	const RESPONSE__TYPE    = "_rt";

	/**
	 * Internal storage for unencoded _PD data.
	 *
	 * @var array
	 */
	static protected $processor_data;

	/**
	 * Handle PROCESSOR_DATA from request parameter _pd
	 *
	 * Convert it to array format (empty array on failure) and merge
	 * obtained array with PHP builded-in $_REQUEST.
	 *
	 * Processing steps:
	 * 1. Decompress processor data
	 * 2. If wrong -> empty array
	 * 3. Merge with REQUEST
	 *
	 * @uses self::PROCESSOR__DATA
	 * @uses self::setProcessorData()
	 *
	 * @return void
	 */
	static public function init() {

		$data = uri()->getElement(self::PROCESSOR__DATA);

		try {

			$data = self::decodeB64Json($data);

		} catch( exception $e ) {

			$data = array();

		}	# try

		$data = array_merge($_REQUEST, $data);

		self::setProcessorData($data);

	}	# Function

	/**
	 * Decode Base64+JSON+URLEncode string data to array.
	 *
	 * Processing steps:
	 * 1. JSON decode
	 * 2. URL decode (some data post from panel wrapped by urlencode)
	 * 3. Log if required
	 *
	 * @param string $_
	 * @return array
	 */
	static public function decodeB64Json($_) {

		if( is_string($_) ) {
			$_ = (array) json_decode( base64_decode($_), TRUE); }

		if( !is_array($_) ) {
			$_ = array(); }

		array_walk_recursive(
			$_,
			create_function('&$_',' return $_ = is_string($_) ? urldecode($_) : $_; ')
		);

		if( panel__settings__environment::isVerbose("panel.application.request.decodeB64Json") ) {

			panel__application::console(
				"panel.application.request.decodeB64Json",
				"Data:", $_
			);

		}	# if

		return $_;

	}	# Function

	/**
	 * @return string
	 */
	static public function getResponseType() {

		return uri()->getElement(self::RESPONSE__TYPE);

	}	# Function

	/**
	 * @param  string $_
	 * @return string
	 */
	static public function setResponseType($_) {

		return uri()->setElement(self::RESPONSE__TYPE, (string) $_);

	}	# Function

	/**
	 * Get requested RRP processor name
	 *
	 *<pre>
	 * Example:
	 * Make request format UI friendly
	 * ja.krevedko = ja__krevedko
	 *</pre>
	 *
	 * @param  bool $_raw_ (Do not perform UI friendly conversion?)
	 * @return string
	 */
	static public function getProcessorName($_raw_ = FALSE) {

		$R = uri()->getElement(self::PROCESSOR__NAME);

		if( !$_raw_ ) {
			$R = str_replace(".", "__", $R); }

		return $R;

	}	# Function

	/**
	 * @param  string $_
	 * @return string
	 */
	static public function setProcessorName($_) {

		return uri()->setElement(self::PROCESSOR__NAME, (string) $_);

	}	# Function

	/**
	 * Get requested RRP processor action
	 *
	 *<pre>
	 * Example:
	 * Make request format UI friendly
	 * ja.krevedko = ja__krevedko
	 *</pre>
	 *
	 * @param  bool $_raw_ (Do not perform UI friendly conversion?)
	 * @return string
	 */
	static public function getProcessorAction($_raw_ = FALSE) {

		$R = uri()->getElement(self::PROCESSOR__ACTION);

		if( !$_raw_ ) {
			$R = str_replace(".", "__", $R); }

		return $R;

	}	# Function

	/**
	 * @param  string $_
	 * @return string
	 */
	static public function setProcessorAction($_) {

		return uri()->setElement(self::PROCESSOR__ACTION, $_);

	}	# Function

	/**
	 * @return array
	 */
	static public function getProcessorData() {

		return self::$processor_data;

	}	# Function

	/**
	 * @param  array $_
	 * @return array
	 */
	static public function setProcessorData( array $_) {

		return self::$processor_data = $_;

	}	# Function

}	# Class

/* EOF */